{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 维基百科词条DeepWalk图嵌入"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 参考资料\n",
    " \n",
    "https://github.com/prateekjoshi565/DeepWalk  \n",
    "一个不错的数据分析网站（翻）：https://www.analyticsvidhya.com/blog/2019/11/graph-feature-extraction-deepwalk/\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import networkx as nx\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import random\n",
    "from tqdm import tqdm #进度条\n",
    "# from sklearn.decomposition import PCA\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "plt.rcParams['font.sans-serif']=['SimHei']  # 用来正常显示中文标签  \n",
    "plt.rcParams['axes.unicode_minus']=False  # 用来正常显示负号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sklearn\n",
    "nx.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://en.wikipedia.org/wiki/Decision_tree  \n",
    "https://en.wikipedia.org/wiki/Computer_vision  \n",
    "https://en.wikipedia.org/wiki/Deep_learning  \n",
    "https://en.wikipedia.org/wiki/Convolutional_neural_network  \n",
    "https://en.wikipedia.org/wiki/Support-vector_machine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv('seealsology-data.tsv',sep='\\t')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建无向图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "G = nx.from_pandas_edgelist(df, \"source\", \"target\", edge_attr=True, create_using=nx.Graph())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(G)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(100,100))\n",
    "nx.draw(G)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 生成随机游走序列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# function to generate random walk sequences of nodes\n",
    "def get_randomwalk(node, path_length):\n",
    "    '''\n",
    "    node：起始节点\n",
    "    path_length：游走序列长度\n",
    "    '''\n",
    "    random_walk = [node]\n",
    "    \n",
    "    for i in range(path_length-1):\n",
    "        temp = list(G.neighbors(node))\n",
    "        temp = list(set(temp) - set(random_walk))    \n",
    "        if len(temp) == 0:\n",
    "            break\n",
    "        # 随机返回temp中的一个结点\n",
    "        random_node = random.choice(temp)\n",
    "        random_walk.append(random_node)\n",
    "        node = random_node\n",
    "        \n",
    "    return random_walk"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_nodes = list(G.nodes())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# all_nodes\n",
    "list(G.neighbors('decision tree model'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "get_randomwalk('random forest',5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gamma = 10 #每个节点生成随机游走序列的个数\n",
    "walk_length = 5 # 游走序列最大长度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "random_walks = []\n",
    "for n in tqdm(all_nodes):\n",
    "    for i in range(gamma):\n",
    "        random_walks.append(get_randomwalk(n,walk_length))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "random_walks[0]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练Word2Vec模型\n",
    "![image.png](Skip-Gram.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from gensim.models import Word2Vec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# train word2vec model\n",
    "model = Word2Vec(vector_size=256,#Embedding维数\n",
    "                 window = 4, \n",
    "                 sg = 1, #Skip-Gram 中心词预测周围词\n",
    "                 hs = 0, #不加分层Softmax\n",
    "                 negative = 10, # for negative sampling负采样\n",
    "                 alpha=0.03, #初始学习率\n",
    "                 min_alpha=0.0007,\n",
    "                 seed = 14 #随机数种子\n",
    "                )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.build_vocab(random_walks, progress_per=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.train(random_walks, total_examples = model.corpus_count, epochs=50, report_delay=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 分解Word2Vec结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看某个节点的Embedding\n",
    "model.wv.get_vector('random forest').shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.wv.get_vector('random forest')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# find top n similar nodes\n",
    "model.wv.similar_by_word('decision tree')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 可视化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### PCA降维"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = model.wv.vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(X)\n",
    "# random_walks[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "terms = ['lunar escape systems','soviet moonshot', 'soyuz 7k-l1', 'moon landing',\n",
    "         'space food', 'food systems on space exploration missions', 'meal, ready-to-eat',\n",
    "         'space law', 'metalaw', 'moon treaty', 'legal aspects of computing',\n",
    "         'astronaut training', 'reduced-gravity aircraft', 'space adaptation syndrome', 'micro-g environment']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pca = PCA(n_components=2)\n",
    "embed_2d = pca.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "embed_2d[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_nodes(node_importance,method):\n",
    "    X = model.wv.vectors\n",
    "    \n",
    "    # reduce dimensions to 2\n",
    "    if method == 'pca':\n",
    "        pca = PCA(n_components=2)\n",
    "        embed_2d = pca.fit_transform(X)\n",
    "    else:\n",
    "        tsne = TSNE(n_components=2, n_iter=1000)\n",
    "        embed_2d = tsne.fit_transform(X)\n",
    "    \n",
    "    plt.figure(figsize=(20,20))\n",
    "    # create a scatter plot of the projection\n",
    "    plt.scatter(embed_2d[:, 0], embed_2d[:, 1])\n",
    "    term2index = model.wv.key_to_index\n",
    "    for name in node_importance:\n",
    "        idx = term2index[name]\n",
    "        plt.scatter(embed_2d[idx,0],embed_2d[idx,1],c='r',s=50)\n",
    "        plt.annotate(name, xy=(embed_2d[idx, 0], embed_2d[idx, 1]),c='k',fontsize=12)\n",
    "        \n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pagerank = nx.pagerank(G)\n",
    "pagerank"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_importance = sorted(pagerank.items(),key=lambda x:x[1], reverse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_name = []\n",
    "for i in range(30):\n",
    "    node_name.append(node_importance[i][0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_name.extend(['deep learning','computer vision','convolution'])\n",
    "node_name = list(set(node_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_nodes(node_name,'pca')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TSNE降维"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.manifold import TSNE\n",
    "X = model.wv.vectors\n",
    "tsne = TSNE(n_components=2, n_iter=1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "embed_2d = tsne.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(14,14))\n",
    "plt.scatter(embed_2d[:,0],embed_2d[:,1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_nodes(node_name,'tsne')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "terms_chosen_mask = np.zeros(X.shape[0])\n",
    "for item in node_name:\n",
    "    term2index = model.wv.key_to_index\n",
    "    idx = term2index[item]\n",
    "    terms_chosen_mask[idx] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pagerank_list = []\n",
    "for i in model.wv.index_to_key:\n",
    "    pagerank_list.append(pagerank[i])\n",
    "    \n",
    "df = pd.DataFrame()\n",
    "df['X'] = embed_2d[:,0]\n",
    "df['Y'] = embed_2d[:,1]\n",
    "df['item'] = model.wv.index_to_key\n",
    "df['pagerank'] = pagerank_list\n",
    "df['chosen'] = terms_chosen_mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.to_csv('tsne_vis_2d.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tsne = TSNE(n_components=3, n_iter=1000)\n",
    "embed_2d = tsne.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pagerank_list = []\n",
    "for i in model.wv.index_to_key:\n",
    "    pagerank_list.append(pagerank[i])\n",
    "    \n",
    "df = pd.DataFrame()\n",
    "df['X'] = embed_2d[:,0]\n",
    "df['Y'] = embed_2d[:,1]\n",
    "df['Z'] = embed_2d[:,2]\n",
    "df['item'] = model.wv.index_to_key\n",
    "df['pagerank'] = pagerank_list\n",
    "df['chosen'] = terms_chosen_mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.to_csv('tsne_vis_3d.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyecharts.charts import Bar\n",
    "\n",
    "bar = Bar()\n",
    "bar.add_xaxis([\"衬衫\", \"羊毛衫\", \"雪纺衫\", \"裤子\", \"高跟鞋\", \"袜子\"])\n",
    "bar.add_yaxis(\"商家A\", [5, 20, 36, 10, 75, 90])\n",
    "# render 会生成本地 HTML 文件，默认会在当前目录生成 render.html 文件\n",
    "# 也可以传入路径参数，如 bar.render(\"mycharts.html\")\n",
    "bar.render()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
